#include "LightingDemo.h"


LightingDemo::LightingDemo(HINSTANCE hInstance, std::string caption)
	: BasicApplication(hInstance, caption)
{
	InitAllVertexDeclarations();

	D3DXCreateTeapot(gd3dDevice, &m_teapot, NULL);	
	genSphericalTexCoords();
	gCamera->pos().z = -10.0f;

	ID3DXBuffer *error = NULL;
	D3DXCreateEffectFromFile(gd3dDevice, "pointLight.fx", NULL, NULL, 
		D3DXSHADER_DEBUG, NULL, &m_effect, &error);
	if(error)
	{
		MessageBox(0, (char*)error->GetBufferPointer(), 0, 0);
		return;
	}

	m_grid = GenTriGrid(100, 100, 10, 10, D3DXVECTOR3(0.0f, 0.0f, 0.0f));

	D3DXCreateTextureFromFile(gd3dDevice, "BeachStones.jpg", &m_gridTexture);
	D3DXCreateTextureFromFile(gd3dDevice, "BumpyMetal.jpg", &m_teapotTexture);
	
	m_hSpotLightTech = m_effect->GetTechniqueByName("PointLightTech");
	m_hWorldViewProj = m_effect->GetParameterByName(0, "gWorldViewProj");
	m_hWorldInvTrans = m_effect->GetParameterByName(0, "gWorldInvTrans");
	m_hWorld = m_effect->GetParameterByName(0, "gWorld");
	m_hAmbientLight = m_effect->GetParameterByName(0, "gAmbientLight");
	m_hDiffuseLight = m_effect->GetParameterByName(0, "gDiffuseLight");
	m_hSpecularLight = m_effect->GetParameterByName(0, "gSpecularLight");
	m_hAmbientMtrl = m_effect->GetParameterByName(0, "gAmbientMtrl");
	m_hDiffuseMtrl = m_effect->GetParameterByName(0, "gDiffuseMtrl");
	m_hSpecularMtrl = m_effect->GetParameterByName(0, "gSpecularMtrl");
	m_hSpecularPower = m_effect->GetParameterByName(0, "gSpecularPower");
	m_hEyePosition = m_effect->GetParameterByName(0, "gEyePosition");
	m_hLightPosition = m_effect->GetParameterByName(0, "gLightPosition");
	m_hLightDir = m_effect->GetParameterByName(0, "gLightDir");
	m_hSpotPower = m_effect->GetParameterByName(0, "gSpotPower");
	m_hTexture0 = m_effect->GetParameterByName(0, "gTexture0");


	D3DXCOLOR ambientLight = 0.4f*WHITE;
	D3DXCOLOR diffuseLight = WHITE;
	D3DXCOLOR specLight = WHITE;
	
	m_matetial = Mtrl(WHITE, WHITE, WHITE, 16.0f);

	D3DXMATRIX identity;
	D3DXMatrixIdentity(&identity);
	m_effect->SetTechnique(m_hSpotLightTech);
	//m_effect->SetMatrix(m_hWorldViewProj, &gCamera->viewProj());
	m_effect->SetMatrix(m_hWorldInvTrans, &identity);
	m_effect->SetMatrix(m_hWorld, &identity);
	m_effect->SetValue(m_hAmbientLight, &ambientLight, sizeof(D3DXCOLOR));
	m_effect->SetValue(m_hDiffuseLight, &diffuseLight, sizeof(D3DXCOLOR));
	m_effect->SetValue(m_hSpecularLight, &specLight, sizeof(D3DXCOLOR));
	m_effect->SetValue(m_hAmbientMtrl,&m_matetial.ambient, sizeof(D3DXCOLOR));
	//m_effect->SetValue(m_hDiffuseMtrl,&m_matetial.diffuse, sizeof(D3DXCOLOR));
	m_effect->SetValue(m_hSpecularMtrl,&m_matetial.spec, sizeof(D3DXCOLOR));
	m_effect->SetFloat(m_hSpecularPower, m_matetial.specPower);
	m_effect->SetValue(m_hEyePosition, &gCamera->pos(), sizeof(D3DXVECTOR3));
	
	m_effect->SetFloat(m_hSpotPower, 2.0f);

	m_lightPosition = D3DXVECTOR3(0.0f, 3.0f, -3.0f);
}

void LightingDemo::onLostDevice()
{
	m_effect->OnLostDevice();
}

void LightingDemo::onResetDevice()
{
	m_effect->OnResetDevice();
}
void LightingDemo::genSphericalTexCoords()
{
	// D3DXCreate* functions generate vertices with position 
	// and normal data.  But for texturing, we also need
	// tex-coords.  So clone the mesh to change the vertex
	// format to a format with tex-coords.

	D3DVERTEXELEMENT9 elements[64];
	UINT numElements = 0;
	VertexPNT::Decl->GetDeclaration(elements, &numElements);

	ID3DXMesh* temp = 0;
	HR(m_teapot->CloneMesh(D3DXMESH_SYSTEMMEM, 
		elements, gd3dDevice, &temp));

	ReleaseCOM(m_teapot);

	// Now generate texture coordinates for each vertex.
	VertexPNT* vertices = 0;
	HR(temp->LockVertexBuffer(0, (void**)&vertices));

	for(UINT i = 0; i < temp->GetNumVertices(); ++i)
	{
		// Convert to spherical coordinates.
		D3DXVECTOR3 p = vertices[i].pos;

		float theta = atan2f(p.z, p.x);
		float phi   = acosf(p.y / sqrtf(p.x*p.x+p.y*p.y+p.z*p.z));

		// Phi and theta give the texture coordinates, but are not in 
		// the range [0, 1], so scale them into that range.

		float u = theta / (2.0f*D3DX_PI);
		float v = phi   / D3DX_PI;

		// Save texture coordinates.

		vertices[i].tex0.x = u;
		vertices[i].tex0.y = v;
	}
	HR(temp->UnlockVertexBuffer());

	// Clone back to a hardware mesh.
	HR(temp->CloneMesh(D3DXMESH_MANAGED | D3DXMESH_WRITEONLY,
		elements, gd3dDevice, &m_teapot));

	ReleaseCOM(temp);
}

LightingDemo::~LightingDemo(void)
{
	ReleaseCOM(m_teapot);
	ReleaseCOM(m_effect);
	ReleaseCOM(m_grid);
	ReleaseCOM(m_gridTexture);
	ReleaseCOM(m_teapotTexture);
}

void LightingDemo::updateScene(float dt)
{
	BasicApplication::updateScene(dt);

	static float t = 0.0f;
	t += dt;
	if( t >= 2.0f*D3DX_PI )
		t = 0.0f;

	D3DXMATRIX Ry;
	D3DXMatrixRotationY(&Ry, t);
	//D3DXVec3TransformCoord(&m_lightPosition, &m_lightPosition, &Ry);
}

void LightingDemo::draw()
{
	D3DXMATRIX teapotWorld, gridWorld;
	D3DXMatrixTranslation(&teapotWorld, 0.0f, 5.0f, 0.0f);
	D3DXMatrixIdentity(&gridWorld);
	
	m_effect->SetValue(m_hLightPosition, &m_lightPosition, sizeof(D3DXVECTOR3));
	//m_effect->SetValue(m_hLightDir, &(-m_lightPosition), sizeof(D3DXVECTOR3));
	UINT pass;
	m_effect->Begin(&pass, 0);
	for(UINT i = 0; i < pass; i++)
	{
		m_effect->BeginPass(i);

		m_effect->SetMatrix(m_hWorldViewProj, &(gridWorld * gCamera->viewProj()));
		m_effect->SetTexture(m_hTexture0, m_gridTexture);
		m_matetial.diffuse.a = 1.0f;
		m_effect->SetValue(m_hDiffuseMtrl,&m_matetial.diffuse, sizeof(D3DXCOLOR));
		m_effect->CommitChanges();
		m_grid->DrawSubset(0);

		m_effect->SetMatrix(m_hWorldViewProj, &(teapotWorld * gCamera->viewProj()));
		m_effect->SetTexture(m_hTexture0, m_teapotTexture);
		m_matetial.diffuse.a = 0.5f;
		m_effect->SetValue(m_hDiffuseMtrl,&m_matetial.diffuse, sizeof(D3DXCOLOR));
		m_effect->CommitChanges();
		m_teapot->DrawSubset(0);

		m_effect->EndPass();
	}
	m_effect->End();
	
}

